package com.zz.framework.core.http

import com.franmontiel.persistentcookiejar.PersistentCookieJar
import com.franmontiel.persistentcookiejar.cache.SetCookieCache
import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor
import com.zz.framework.BuildConfig
import com.zz.framework.core.BaseApp
import com.zz.framework.core.http.intercept.LoggingIntercept
import com.zz.framework.core.utils.NetWorkUtils
import com.zz.framework.core.config.GlobalSetting
import okhttp3.*
import java.io.File
import java.net.Proxy
import java.security.SecureRandom
import java.util.*
import java.util.concurrent.TimeUnit
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager

/**
 * Copyright © 2020 zanezhao All rights reserved.
 * Created by zanezhao on 2020/3/1 1:15 PM.//////
 * @author: zanezhao 1820022519@qq.com
 * @version: V1.0
 */
object BaseOkHttpClient {
    // 初始化 okHttp
    fun create(vararg interceptors: Interceptor,blockBuilder:((OkHttpClient.Builder)->Unit) = {
        defaultHandleBuilder(it)
    }): OkHttpClient {
        val builder = OkHttpClient.Builder()
        interceptors.forEach {
            builder.addInterceptor(it)
        }
//        builder.addNetworkInterceptor(Ok2CulInterceptor.builder())
        builder.addInterceptor(LoggingIntercept.init())
            .readTimeout(GlobalSetting.READ_TIME_OUT, TimeUnit.SECONDS)
            .writeTimeout(GlobalSetting.WRITE_TIME_OUT, TimeUnit.SECONDS)
            .connectTimeout(GlobalSetting.CONNECT_TIME_OUT, TimeUnit.SECONDS)
            .protocols(Collections.unmodifiableList(Arrays.asList(Protocol.HTTP_1_1, Protocol.HTTP_2)))
        if (BuildConfig.DEBUG.not()) {
            builder.proxy(Proxy.NO_PROXY)
        }
        try {
            blockBuilder.invoke(builder)
        }catch (e:Exception){
            e.printStackTrace()
        }
        val mClient = builder.build()
        ignoreSSLCheck(mClient)
        return mClient
    }


    private val cookieJar by lazy {
        PersistentCookieJar(SetCookieCache(), SharedPrefsCookiePersistor(BaseApp.context))
    }

     private fun defaultHandleBuilder(builder: OkHttpClient.Builder) {
        val httpCacheDirectory = File(BaseApp.context.cacheDir, "responses")
        val cacheSize = 10 * 1024 * 1024L // 10 MiB
        val cache = Cache(httpCacheDirectory, cacheSize)
        builder.cache(cache)
            .cookieJar(cookieJar)
            .addInterceptor { chain ->
                var request = chain.request()
                if (!NetWorkUtils.isNetworkAvailable(BaseApp.context)) {
                    request = request.newBuilder()
                        .cacheControl(CacheControl.FORCE_CACHE)
                        .build()
                }
                val response = chain.proceed(request)
                if (!NetWorkUtils.isNetworkAvailable(BaseApp.context)) {
                    val maxAge = 60 * 60
                    response.newBuilder()
                        .removeHeader("Pragma")
                        .header("Cache-Control", "public, max-age=$maxAge")
                        .build()
                } else {
                    val maxStale = 60 * 60 * 24 * 28 // tolerate 4-weeks stale
                    response.newBuilder()
                        .removeHeader("Pragma")
                        .header("Cache-Control", "public, only-if-cached, max-stale=$maxStale")
                        .build()
                }
                response
            }
    }

    private fun ignoreSSLCheck(mClient: OkHttpClient) {
        var sc: SSLContext? = null
        try {
            sc = SSLContext.getInstance("SSL")
            sc!!.init(null, arrayOf<TrustManager>(object : X509TrustManager {
                @Throws(java.security.cert.CertificateException::class)
                override fun checkClientTrusted(
                    chain: Array<java.security.cert.X509Certificate>,
                    authType: String
                ) {

                }

                @Throws(java.security.cert.CertificateException::class)
                override fun checkServerTrusted(
                    chain: Array<java.security.cert.X509Certificate>,
                    authType: String
                ) {

                }

                override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate>? {
                    return null
                }
            }), SecureRandom())
        } catch (e: Exception) {
            e.printStackTrace()
        }

        val hv1 = HostnameVerifier { hostname, session -> true }
        val workerClassName = "okhttp3.OkHttpClient"
        try {
            val workerClass = Class.forName(workerClassName)
            val hostnameVerifier = workerClass.getDeclaredField("hostnameVerifier")
            hostnameVerifier.isAccessible = true
            hostnameVerifier.set(mClient, hv1)

            val sslSocketFactory = workerClass.getDeclaredField("sslSocketFactory")
            sslSocketFactory.isAccessible = true
            sslSocketFactory.set(mClient, sc!!.socketFactory)
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }
}